package com.nbcio.iot.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.nbcio.common.core.domain.R;
import com.nbcio.iot.domain.entity.IotControlRecord;
import com.nbcio.iot.mapper.IotControlRecordMapper;
import com.nbcio.iot.protocol.modbus.ModbusManager;
import com.nbcio.iot.protocol.mqtt.MqttClientManager;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.*;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@RestController
@RequestMapping("/iot/control")
@RequiredArgsConstructor
public class IotControlController {

    private final MqttClientManager mqttClientManager;
    private final ModbusManager modbusManager;
    private final IotControlRecordMapper controlRecordMapper;
    private final ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 控制记录分页查询
     */
    @GetMapping("/records")
    public R<Page<IotControlRecord>> records(
            @RequestParam(required = false) Long deviceId,
            @RequestParam(required = false) String deviceCode,
            @RequestParam(required = false) String channel,
            @RequestParam(required = false) String action,
            @RequestParam(required = false) String status,
            @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date beginTime,
            @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date endTime,
            @RequestParam(defaultValue = "1") long pageNum,
            @RequestParam(defaultValue = "10") long pageSize
    ) {
        LambdaQueryWrapper<IotControlRecord> qw = new LambdaQueryWrapper<>();
        if (deviceId != null) qw.eq(IotControlRecord::getDeviceId, deviceId);
        if (deviceCode != null && !deviceCode.isEmpty()) qw.like(IotControlRecord::getDeviceCode, deviceCode);
        if (channel != null && !channel.isEmpty()) qw.eq(IotControlRecord::getChannel, channel);
        if (action != null && !action.isEmpty()) qw.eq(IotControlRecord::getAction, action);
        if (status != null && !status.isEmpty()) qw.eq(IotControlRecord::getStatus, status);
        if (beginTime != null) qw.ge(IotControlRecord::getCreateTime, beginTime);
        if (endTime != null) qw.le(IotControlRecord::getCreateTime, endTime);
        qw.orderByDesc(IotControlRecord::getCreateTime);
        Page<IotControlRecord> page = controlRecordMapper.selectPage(new Page<>(pageNum, pageSize), qw);
        return R.ok(page);
    }

    /**
     * 通过 MQTT 下发控制
     */
    @PostMapping("/mqtt/publish")
    public R<Void> mqttPublish(@RequestBody Map<String, Object> body) {
        String topic = (String) body.get("topic");
        String payload = (String) body.get("payload");
        Long deviceId = body.get("deviceId") == null ? null : Long.valueOf(String.valueOf(body.get("deviceId")));
        String deviceCode = (String) body.get("deviceCode");
        IotControlRecord rec = new IotControlRecord();
        rec.setDeviceId(deviceId);
        rec.setDeviceCode(deviceCode);
        rec.setChannel("MQTT");
        rec.setAction("mqtt-publish");
        try {
            Map<String,Object> req = new HashMap<>(body);
            rec.setRequest(objectMapper.writeValueAsString(req));
            mqttClientManager.publish(topic, payload);
            rec.setStatus("SUCCESS");
            rec.setResponse("OK");
            controlRecordMapper.insert(rec);
            return R.ok();
        } catch (Exception e) {
            log.warn("mqtt publish failed: {}", e.getMessage());
            try { rec.setResponse(e.getMessage()); } catch (Exception ignore) {}
            rec.setStatus("FAIL");
            controlRecordMapper.insert(rec);
            return R.fail("MQTT 发布失败: " + e.getMessage());
        }
    }

    /**
     * 通过 Modbus 写入保持寄存器
     */
    @PostMapping("/modbus/writeHolding")
    public R<Void> modbusWriteHolding(@RequestBody Map<String, Object> body) {
        int slaveId = Integer.parseInt(String.valueOf(body.get("slaveId")));
        int offset = Integer.parseInt(String.valueOf(body.get("offset")));
        int value = Integer.parseInt(String.valueOf(body.get("value")));
        String proto = String.valueOf(body.getOrDefault("protocol", "TCP")); // TCP/RTU
        Long deviceId = body.get("deviceId") == null ? null : Long.valueOf(String.valueOf(body.get("deviceId")));
        String deviceCode = (String) body.get("deviceCode");

        IotControlRecord rec = new IotControlRecord();
        rec.setDeviceId(deviceId);
        rec.setDeviceCode(deviceCode);
        rec.setChannel("MODBUS");
        rec.setAction("modbus-write-holding");
        try {
            rec.setRequest(objectMapper.writeValueAsString(body));
            if ("RTU".equalsIgnoreCase(proto)) {
                modbusManager.writeHoldingRegisterRtu(slaveId, offset, value);
            } else {
                modbusManager.writeHoldingRegisterTcp(slaveId, offset, value);
            }
            rec.setStatus("SUCCESS");
            rec.setResponse("OK");
            controlRecordMapper.insert(rec);
            return R.ok();
        } catch (Exception e) {
            log.warn("modbus write failed: {}", e.getMessage());
            try { rec.setResponse(e.getMessage()); } catch (Exception ignore) {}
            rec.setStatus("FAIL");
            controlRecordMapper.insert(rec);
            return R.fail("Modbus 写入失败: " + e.getMessage());
        }
    }
} 